package cn.le.io;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.concurrent.TimeUnit;

/**
 *jdk1.4引入的文件枷锁机制,允许我们同步访问某个共享资源的文件,不过,竞争同一个文件的两个线程
 *可能不在同一个Java虚拟机上,或者是一个Java进程,另一个是操作系统中其他的某个本地线程,
 *文件锁对其他的操心系统进程是可见的,因为java的文件枷锁直接映射到了本地操作系统的枷锁工具
 *
 */
public class FileLocking {

    public static void main(String[] args) throws Exception {

        FileLocking.lockingMappedFiles();
    }

    public static void fileLock() throws Exception {
        FileOutputStream fos = new FileOutputStream("d:\\file.txt");
        //对fileChannel调用tryLock()或者lock(),就可以获取整个文件的fileLock,
        //tryLock()是非阻塞的,会直接从方法调用返回,lock()是阻塞的,它要阻塞进程到直至锁可以获取,
        //或调用lock()的线程中断,或调用的通道关闭
        FileLock fl = fos.getChannel().tryLock();
        System.out.println(fl.isShared());
        if(fl != null)
        {
            System.out.println("locked file");
            TimeUnit.MILLISECONDS.sleep(100);
            //释放锁
            fl.release();
            System.out.println("Released lock");
        }
        fos.close();
        //部分枷锁
        //position:起始位置  seize:长度  shared:是否是共享所
        fos.getChannel().tryLock(0,1000,true);
        fos.getChannel().lock(0,1000,true);

        //独立锁和共享锁是由操作系统系统的,FileLock.isShared()查询锁的类型,此方法是判定锁定是否为共享锁
        System.out.println(fl.isShared());
    }

    static final int LENGTH = 10000;
    static FileChannel fc;
    public static void lockingMappedFiles() throws Exception {

        fc = new RandomAccessFile("d:\\text.dat","rw").getChannel();
        MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE,0,LENGTH);
        for (int i = 0; i < LENGTH; i++) {
            out.put((byte)'x');

            new LockAndModify(out,0,LENGTH/2);
            new LockAndModify(out,0,LENGTH/2);
        }
    }
    public static class LockAndModify extends  Thread {

        private ByteBuffer buffer;
        private int start,end;
        LockAndModify(ByteBuffer mbb,int start,int end)
        {
            this.start = start;
            this.end = end;
            mbb.limit(end);
            mbb.position(start);
            buffer = mbb.slice();
            start();
        }

        public void run()
        {
            try {

                FileLock fl = fc.lock(start,end,false);
                System.out.println(this.getName()
                        +"locked: "+start+" to "+end);
                while (buffer.position() <  buffer.limit() - 1)
                {
                    buffer.put((byte)(buffer.get()+1));
                }
                fl.release();
                System.out.println("Released: "+start+" to "+ end);
            }catch (IOException e)
            {
                e.printStackTrace();
            }

        }
    }
}

